package func.study.concurrency.c12;

import java.util.concurrent.Semaphore;

/**
 * Created by chenyao on 2017/7/17.
 */
public class NewBoundedBuffer<E> {
    private final Semaphore availableItems;
    private final Semaphore availableSpaces;
    private final E[] items;
    private int putPosition =0, takePosition = 0;

    public NewBoundedBuffer(int capacity) {
        this.availableItems = new Semaphore(0);
        this.availableSpaces = new Semaphore(capacity);
        this.items = (E[]) new Object[capacity];
    }

    public boolean isEmpty() {
        return availableItems.availablePermits() == 0;
    }
    public boolean isFull() {
        return availableSpaces.availablePermits() == 0;
    }

    public void put(E x) throws InterruptedException {
        availableSpaces.acquire();
        doInsert(x);
        availableItems.release();
    }

    private synchronized void doInsert(E x) {
        int i = putPosition;
        items[i] = x;
        putPosition = (++i == items.length) ? 0 : i;
    }

    public E take() throws InterruptedException {
        availableItems.acquire();
        E item = doExtract();
        availableSpaces.release();
        return item;
    }


    private E doExtract() {
        int i = takePosition;
        E x = items[i];
        takePosition = (++i == items.length) ? 0 : i;
        return x;
    }

    public static void main(String[] args) {
        //测试，断言它的后验条件和不变约束
        //先顺序化测试，确保可能的错误还没有涉及并发问题就发现它们
        NewBoundedBuffer<Integer> buffer = new NewBoundedBuffer<>(10);
        //1.新建立的缓存，应该确定自己是空的，同时不是满的
       /* Assert.assertTrue(buffer.isEmpty());
        Assert.assertFalse(buffer.isFull());*/


        //2.把N个元素插入N容量缓存中，然后测试，是否已经满了，非空
        /*for (int i = 0; i < 10; i++) {
            buffer.put(i);
        }
        Assert.assertTrue(buffer.isFull());
        Assert.assertFalse(buffer.isEmpty());*/


        //测试并发的本质属性是，需要引入更多的线程

        /**
         * 每个测试在它创建的所有线程终止前，必须等待
         *
         */
        //testTakeBlocksWhenEmpty();
        System.out.println(xorShift(3));
    }

    static void testTakeBlocksWhenEmpty() {
        final NewBoundedBuffer<Integer> buffer = new NewBoundedBuffer<>(10);
        Thread taker = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    buffer.take();
                    fail(); //如果运行到这里，说明有错误
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        try {
            taker.start();
           // Thread.sleep(1000);
            //taker.interrupt();
           // taker.join(1000);
          //  Assert.assertFalse(taker.isAlive());
            taker.join(1000);
            buffer.put(1);
        } catch (Exception e) {
            fail();
        }
    }


    private static void fail() {
        System.out.println("fail");
    }

    static int xorShift(int y) {
        y ^= (y << 6);
        y ^= (y >>> 21);
        y ^= (y << 7);
        return y;
    }


}
